package org.takeback.chat.service;

import com.google.common.collect.ImmutableMap;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.takeback.chat.entity.GcLottery;
import org.takeback.chat.entity.GcLotteryDetail;
import org.takeback.chat.entity.Message;
import org.takeback.chat.lottery.Lottery;
import org.takeback.chat.lottery.LotteryDetail;
import org.takeback.chat.store.room.LotteryFactory;
import org.takeback.chat.store.room.Room;
import org.takeback.chat.store.room.RoomStore;
import org.takeback.chat.store.user.User;
import org.takeback.chat.store.user.UserStore;
import org.takeback.chat.utils.MessageUtils;
import org.takeback.chat.utils.NumberUtil;
import org.takeback.service.BaseService;
import org.takeback.util.BeanUtils;
import org.takeback.util.exception.CodedBaseRuntimeException;

@Service("game01Service")
public class Game01Service extends BaseService {
	@Autowired
	private RoomStore roomStore;
	@Autowired
	private UserStore userStore;
	@Autowired
	private GameMonitor monitor;
	@Autowired
	LotteryService lotteryService;

	@Transactional(rollbackFor = { Throwable.class })
	public void dealResult(Lottery lottery, Room room) {
		Integer looserId = who(lottery, room);
		User looser = (User) this.userStore.get(looserId);

		clear(lottery, room, looserId);

		clearRoom(lottery, room);

		Map<String, Object> p = room.getProperties();
		Integer delay = Integer.valueOf(0);
		try {
			delay = Integer.valueOf(p.get("conf_rest_time").toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
		noticeResult(room, lottery, looserId, delay);

		sendNew(room, looser, delay);
		String msg = (new StringBuffer("<span style='color:#B22222'>你手气糟糕,下个红包由你发出!</span>")).toString();
		MessageUtils.send(looserId, room, new Message("TXT_SYS", looserId, msg));
	}

	private void noticeResult(Room room, Lottery lottery, Integer looserId, Integer delay) {
		Integer luckyId = whoLucky(lottery);
		LotteryDetail luckyDetail = (LotteryDetail) lottery.getDetail().get(luckyId);
		User looser = (User) this.userStore.get(looserId);
		User lucky = (User) this.userStore.get(luckyId);
		LotteryDetail badLuckDetail = (LotteryDetail) lottery.getDetail().get(looserId);

		String msg = "最佳手气 <span style='color:red'>" + lucky.getNickName() + " (" + luckyDetail.getCoin()
				+ "金币)</span><br>" + "手气最差 <span style='color:green'>" + looser.getNickName() + "("
				+ badLuckDetail.getCoin() + "金币)</span>";
		MessageUtils.broadcast(room, new Message("TXT_SYS", Integer.valueOf(0), msg));

		String msg1 = "<span style='color:red'><strong>" + delay + "秒后系统发出红包,准备开开抢!</strong></span>";
		MessageUtils.broadcast(room, new Message("TXT_SYS", Integer.valueOf(0), msg1));
		if (delay.intValue() > 5) {
			Integer half = Integer.valueOf(delay.intValue() / 2);
			String msg2 = "<span style='color:red'><strong>" + (delay.intValue() - half.intValue())
					+ "秒倒计时,袖子抡起!</strong></span>";
			MessageUtils.broadcastDelay(room, new Message("TXT_SYS", Integer.valueOf(0), msg2), half.intValue());
		}
	}

	@Transactional(rollbackFor = { Throwable.class })
	public void sendNew(Room room, User looser, Integer delay) {
		Message message = new Message();
		message.setType("RED");
		message.setHeadImg(looser.getHeadImg());
		message.setNickName(looser.getNickName());

		Map<String, Object> properties = room.getProperties();
		BigDecimal money = new BigDecimal(properties.get("conf_money").toString());
        if (room.getPoolAdd() != null && room.getPoolAdd() > 0.0) {
            money = money.subtract(new BigDecimal(room.getPoolAdd()));
        }
        if (room.getFeeAdd() != null && room.getFeeAdd() > 0.0) {
            money = money.subtract(new BigDecimal(room.getFeeAdd()));
        }
		Integer number = Integer.valueOf(properties.get("conf_size").toString());
		String description = StringUtils.isEmpty(properties.get("conf_title").toString()) ? "恭喜发财"
				: properties.get("conf_title").toString();
		Integer expired = Integer.valueOf(properties.get("conf_expired").toString());
		Map<String, Object> content = new HashMap();
		content.put("money", money);
		content.put("number", number);
		content.put("description", description);
		message.setContent(content);
		Map<String, Object> body = (Map) message.getContent();

		Lottery red = LotteryFactory.getDefaultBuilder(money, number).setDescription("恭喜发财，大吉大利")
				.setSender(looser.getId().intValue()).setType("2").setRoom(room).setExpiredSeconds(expired).build();
		GcLottery gcLottery = (GcLottery) BeanUtils.map(red, GcLottery.class);
		this.dao.save(GcLottery.class, gcLottery);
		Message redMessage = (Message) BeanUtils.map(message, Message.class);
		redMessage.setContent(red);
		redMessage.setSender(looser.getId());

		this.lotteryService.setBackWater(looser.getId(), room.getFeeAdd());

		MessageUtils.broadcastDelay(room, redMessage, delay.intValue());
	}

	@Transactional(rollbackFor = { Throwable.class })
	public void gameLotteryExpired(Lottery lottery, Room room) {
		Map<Integer, LotteryDetail> detail = lottery.getDetail();
		Iterator itr = detail.keySet().iterator();
		Map<String, Object> romProps = room.getProperties();
		BigDecimal redMoney = new BigDecimal(Double.valueOf(romProps.get("conf_money").toString()).doubleValue());
		StringBuffer hql = new StringBuffer("update PubUser a set a.money = COALESCE(a.money,0)+:money where a.id in(");
		StringBuilder sb = new StringBuilder();
		while (itr.hasNext()) {
			Integer uid = (Integer) itr.next();
			sb.append(uid).append(",");
		}
		if (sb.length() > 0) {
			sb = sb.deleteCharAt(sb.length() - 1);
			hql = hql.append(sb).append(")");
			this.dao.executeUpdate(hql.toString(), ImmutableMap.of("money", Double.valueOf(redMoney.doubleValue())));
		}
		if (!lottery.getSender().equals(Integer.valueOf(0))) {
			BigDecimal retn = redMoney.subtract(new BigDecimal(1));
			this.dao.executeUpdate("update PubUser a set a.money = COALESCE(a.money,0)+:money where a.id=:id",
					ImmutableMap.of("money", Double.valueOf(retn.doubleValue()), "id", lottery.getSender()));
		}
		this.dao.executeUpdate("update GcLottery a set a.status = '2' where a.id = :id and a.status = '0'",
				ImmutableMap.of("id", lottery.getId()));
		this.dao.executeUpdate("update GcRoom a set a.status=0 where id =:id ",
				ImmutableMap.of("id", lottery.getRoomId()));
	}

	@Transactional(rollbackFor = { Throwable.class })
	public void clear(Lottery lottery, Room room, Integer looserId) {
		Map<Integer, LotteryDetail> detail = lottery.getDetail();
		Iterator itr = detail.keySet().iterator();
		Map<String, Object> romProps = room.getProperties();
		BigDecimal redMoney = new BigDecimal(Double.valueOf(romProps.get("conf_money").toString()).doubleValue());
		while (itr.hasNext()) {
			Integer uid = (Integer) itr.next();
			User user = (User) this.userStore.get(uid);
			LotteryDetail d = (LotteryDetail) detail.get(uid);
			BigDecimal money = d.getCoin();
			if (!user.getId().equals(looserId)) {
				money = money.add(redMoney);
			}
			String key = "b_" + money.toString();
			if (romProps.containsKey(key)) {
				Double value = Double.valueOf(romProps.get(key).toString());

				this.dao.executeUpdate("update GcRoom set sumPool = COALESCE(sumPool,0)-:bonus where id =:roomId ",
						ImmutableMap.of("bonus", value, "roomId", room.getId()));
				money = money.add(new BigDecimal(value.doubleValue()));
				String msg = "<span style='color:#B22222'>" + user.getNickName()
						+ " 手气超好,获得奖金</span><span style='font-size:16;color:red'>￥" + value + "</span>";
				MessageUtils.broadcast(room, new Message("TXT_SYS", uid, msg));
			}
			GcLotteryDetail gcLotteryDetail = (GcLotteryDetail) BeanUtils.map(detail, GcLotteryDetail.class);
			gcLotteryDetail.setLotteryid(lottery.getId());
			gcLotteryDetail.setCoin(d.getCoin());
			gcLotteryDetail.setGameType("G011");
			gcLotteryDetail.setDesc1("幸运");
			gcLotteryDetail.setRoomId(room.getId());
			gcLotteryDetail.setUid(uid);
			gcLotteryDetail.setDeposit(redMoney.doubleValue());
			gcLotteryDetail.setAddback(NumberUtil.round(money.doubleValue()));
			Double inout = Double.valueOf(NumberUtil.round(money.subtract(redMoney).doubleValue()));
			if (user.getId().equals(looserId)) {
				inout = Double.valueOf(NumberUtil.round(d.getCoin().subtract(redMoney).doubleValue()));
				gcLotteryDetail.setDesc1("最差手气");
			}
			gcLotteryDetail.setInoutNum(inout.doubleValue());

			this.monitor.setData(room.getId(), user.getId(), inout);

			gcLotteryDetail.setCreateDate(new Date());
			this.dao.save(GcLotteryDetail.class, gcLotteryDetail);
			this.dao.executeUpdate(
					"update PubUser set money = COALESCE(money,0)+:money ,exp = coalesce(exp,0)+:exp where id=:uid ",
					ImmutableMap.of("money", Double.valueOf(money.doubleValue()), "exp",
							Double.valueOf(redMoney.doubleValue()), "uid", uid));
		}
	}

	@Transactional(rollbackFor = { Throwable.class })
	public void clearRoom(Lottery lottery, Room room) {
		if (lottery.getSender().equals(Integer.valueOf(0))) {
			return;
		}
		Double poolAdd = Double.valueOf(0.0D);
		Double feeAdd = Double.valueOf(0.0D);
		if ((room.getPoolAdd() != null) && (room.getPoolAdd().doubleValue() > 0.0D)) {
			poolAdd = room.getPoolAdd();
		}
		if ((room.getFeeAdd() != null) && (room.getFeeAdd().doubleValue() > 0.0D)) {
			feeAdd = room.getFeeAdd();
		}
		if ((poolAdd.doubleValue() == 0.0D) && (feeAdd.doubleValue() == 0.0D)) {
			return;
		}
		String hql = "update GcRoom set sumPool = COALESCE(sumPool,0) + :poolAdd , sumFee = COALESCE(sumFee,0) + :feeAdd ,sumPack = COALESCE(sumPack,0)+1 where id =:roomId";
		this.dao.executeUpdate(hql, ImmutableMap.of("poolAdd", poolAdd, "feeAdd", feeAdd, "roomId", room.getId()));
	}

	private Integer whoLucky(Lottery lottery) {
		Map<Integer, LotteryDetail> detail = lottery.getDetail();
		Iterator itr = detail.keySet().iterator();
		Integer luckyId = null;
		BigDecimal num = null;
		while (itr.hasNext()) {
			Integer uid = (Integer) itr.next();
			LotteryDetail d = (LotteryDetail) detail.get(uid);
			if (num == null) {
				num = d.getCoin();
				luckyId = uid;
			} else if (num.compareTo(d.getCoin()) < 0) {
				num = d.getCoin();
				luckyId = uid;
			}
		}
		return luckyId;
	}

	private Integer who(Lottery lottery, Room room) {
		Map<String, Object> romProps = room.getProperties();
		if (romProps.get("conf_looser") == null) {
			throw new CodedBaseRuntimeException("配置丢失!");
		}
		Integer unDead = room.getUnDead();
		String rule = romProps.get("conf_looser").toString();
		Map<Integer, LotteryDetail> detail = lottery.getDetail();
		Iterator itr = detail.keySet().iterator();
		Integer looserId = null;
		BigDecimal mem = null;
		if ("max".equals(rule)) {
			while (itr.hasNext()) {
				Integer uid = (Integer) itr.next();
				if (!uid.equals(unDead)) {
					LotteryDetail d = (LotteryDetail) detail.get(uid);
					if (mem == null) {
						mem = d.getCoin();
						looserId = uid;
					} else if (mem.compareTo(d.getCoin()) < 0) {
						mem = d.getCoin();
						looserId = uid;
					}
				}
			}
		}
		if ("min".equals(rule)) {
			while (itr.hasNext()) {
				Integer uid = (Integer) itr.next();
				if (!uid.equals(unDead)) {
					LotteryDetail d = (LotteryDetail) detail.get(uid);
					if (mem == null) {
						mem = d.getCoin();
						looserId = uid;
					} else if (mem.compareTo(d.getCoin()) > 0) {
						mem = d.getCoin();
						looserId = uid;
					}
				}
			}
		}
		if ("tail_max".equals(rule)) {
			while (itr.hasNext()) {
				Integer uid = (Integer) itr.next();
				if (!uid.equals(unDead)) {
					LotteryDetail d = (LotteryDetail) detail.get(uid);
					if (mem == null) {
						mem = NumberUtil.getDecimalPart(d.getCoin());
						looserId = uid;
					} else if (mem.compareTo(d.getCoin()) > 0) {
						mem = NumberUtil.getDecimalPart(d.getCoin());
						looserId = uid;
					}
				}
			}
		}
		if ("tail_min".equals(rule)) {
			while (itr.hasNext()) {
				Integer uid = (Integer) itr.next();
				if (!uid.equals(unDead)) {
					LotteryDetail d = (LotteryDetail) detail.get(uid);
					if (mem == null) {
						mem = NumberUtil.getDecimalPart(d.getCoin());
						looserId = uid;
					} else if (mem.compareTo(d.getCoin()) < 0) {
						mem = mem = NumberUtil.getDecimalPart(d.getCoin());
						looserId = uid;
					}
				}
			}
		}
		if (!"tail_sum_max".equals(rule)) {
			if (!"tail_sum_min".equals(rule)) {
				if (!"sum_max".equals(rule)) {
					if (!"sum_min".equals(rule)) {
					}
				}
			}
		}
		return looserId;
	}

	@Transactional(rollbackFor = { Throwable.class })
	public Double test() {
		List<Double> l = this.dao
				.findByHql("select sum(money)+(select sumFee+sumPool from GcRoom where id='1001') from PubUser");
		return (Double) l.get(0);
	}
}
